package com.nulldev.util.image2.textobf;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import com.nulldev.util.image.ImageUtil;
import com.nulldev.util.java.CloneUtils;
import com.nulldev.util.java.swing.SwingUtil;
import com.nulldev.util.java.swing.font.FontManager;
import com.nulldev.util.java.utils.color.ColorUtil;
import com.nulldev.util.math.MathUtil;

public class TextObf {
	
	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * <s>Method: Random Pixels</s>
	 * @param text
	 * @return Obfuscated BufferedImage
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method) {
		return obfuscate(text, method, false, FontManager.getFontSet());
	}

	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * <s>Method: Random Pixels</s>
	 * @param text
	 * @return Obfuscated BufferedImage
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method, final Font font) {
		return obfuscate(text, method, false, font);
	}
	
	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * <s>Method: Random Pixels</s>
	 * @param text
	 * @return Obfuscated BufferedImage
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method, 
			final boolean _imageboardformatting) {
		return obfuscate(text, method, _imageboardformatting, FontManager.getFontSet());
	}
	
	/**
	 * Obfuscates an image. Use \n for a new line. <br>
	 * <s>Method: Random Pixels</s>
	 * @param text
	 * @return Obfuscated BufferedImage or null if no method provided
	 */
	public static BufferedImage obfuscate(final String text, final ObfuscationMethod method, 
			final boolean _imageboardformatting, final Font font) {
		BufferedImage pre = ImageUtil.createFromColorImg(Color.WHITE, 240, 60);
		final Graphics g0 = pre.getGraphics();
		g0.setFont(font);
		((Graphics2D) g0).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		final String[] lines = text.split("\n");
		final int height = (int) (lines.length * (font.getSize() * 1.2));
		int longest = 0;
		for (final String line : lines) {
			final int length = (int) (SwingUtil.stringWidth(g0.getFontMetrics(), line) * 1.6) 
					+ g0.getFontMetrics().getMaxAscent() + g0.getFontMetrics().getMaxDescent();
			if (longest == 0) {
				longest = (int) (length + (g0.getFont().getSize() * 1.8));
			}else {
				if (longest > length) {
					longest = (int) (length + (g0.getFont().getSize() * 1.8));
				}
			}
		}
		g0.dispose();
		pre = ImageUtil.createFromColorImg(Color.WHITE, longest, height);
		final Graphics g = pre.getGraphics();
		g.setFont(font);
		((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		final Color DEFAULT_COLOR = (method == ObfuscationMethod.Noise ? ColorUtil.randomColor() : Color.BLACK);
		g.setColor(DEFAULT_COLOR);
		int y = 15;
		for (final String line : lines) {
			if (_imageboardformatting) {
				if (line.startsWith(">") && !line.startsWith(">>")) {
					g.setColor(ColorUtil.GREEN);
					g.drawString(line, 5, y);
					g.setColor(DEFAULT_COLOR);
				}else if (line.startsWith(">>")) {
					g.setColor(Color.RED);
					g.drawString(line, 5, y);
					g.setColor(DEFAULT_COLOR);
				}else {
					g.setColor(DEFAULT_COLOR);
					g.drawString(line, 5, y);
				}
			}else {
				g.drawString(line, 5, y);
			}
			y += 15;
		}
		g.dispose();
		return obf(method, pre);
	}
	
	public static BufferedImage obfuscateImage(final BufferedImage image, final ObfuscationMethod method) {
		return obf(method, image);
	}
	
	private static BufferedImage obf(final ObfuscationMethod method, final BufferedImage pre) {
		if (method == ObfuscationMethod.PixelObfuscation) {
			BufferedImage obf = CloneUtils.clone(pre);
			final Graphics go = obf.getGraphics();
			for (int i = 0; i < obf.getWidth() / 2; i++) {
				go.setColor(ColorUtil.randomColor());
				go.drawRect(MathUtil.randInt(0, obf.getWidth()), MathUtil.randInt(0, obf.getHeight()), 1, 1);
			}
			go.dispose();
			return obf;
		}else if (method == ObfuscationMethod.DualPixelObfuscation) {
			BufferedImage obf = CloneUtils.clone(pre);
			final Graphics go = obf.getGraphics();
			for (int i = 0; i < obf.getWidth() / 2; i++) {
				go.setColor(ColorUtil.randomColor());
				go.drawRect(MathUtil.randInt(0, obf.getWidth()), MathUtil.randInt(0, obf.getHeight()), 1, 1);
			}
			for (int i = 0; i < obf.getWidth() / 2; i++) {
				go.setColor(ColorUtil.randomColor());
				go.drawRect(MathUtil.randInt(0, obf.getWidth()), MathUtil.randInt(0, obf.getHeight()), 1, 1);
			}
			go.dispose();
			return obf;	
		}else if (method == ObfuscationMethod.Noise) {
			BufferedImage obf = CloneUtils.clone(pre);
			for (int x = 0; x < obf.getWidth(); x++) {
				for (int y0 = 0; y0 < obf.getHeight(); y0++) {
					final Color t = new Color(obf.getRGB(x, y0));
					if (t != Color.BLACK) {
						obf.setRGB(x, y0, obf.getRGB(x, y0) + MathUtil.randInt(1, 6000));
					}
				}
			}
			return obf;
		}else if (method == ObfuscationMethod.PixelsAndNoise) {
			BufferedImage obf = CloneUtils.clone(pre);
			for (int x = 0; x < obf.getWidth(); x++) {
				for (int y0 = 0; y0 < obf.getHeight(); y0++) {
					final Color t = new Color(obf.getRGB(x, y0));
					if (t != Color.BLACK) {
						obf.setRGB(x, y0, obf.getRGB(x, y0) + MathUtil.randInt(1, 6000));
					}
				}
			}
			final Graphics go = obf.getGraphics();
			for (int i = 0; i < obf.getWidth() / 2; i++) {
				go.setColor(ColorUtil.randomColor());
				go.drawRect(MathUtil.randInt(0, obf.getWidth()), MathUtil.randInt(0, obf.getHeight()), 1, 1);
			}
			go.dispose();
			return obf;
		}
		return pre;
	}
	
	public static enum ObfuscationMethod {
		PixelObfuscation, DualPixelObfuscation, Noise, PixelsAndNoise, None
	}
}
